/* 最小点权覆盖集
* 1.点覆盖集 
    满足图中每一条边所连的两点至少有一个被选的点集

* 2.最小点权覆盖集
    使得所有边都至少有一个端点在点集内，且这样的点集的权值之和最小
    最小权点覆盖在一般图中是 NPC问题 (Non-Deterministic Polynomial-complete 问题即非确定性多项式完全问题)，针对二分图有很好的效果

* 3.图与流转换
    对于一个二分图，考虑转换为流网络，建立一个源点 s，s 向二分图左部的所有点连边，容量为点权，
                                   建立一个汇点 t，二分图右部的所有点向 t 连边，容量为点权，
    原二分图中的边在流网络中容量足够大，证明时只用考虑简单割和极小点覆盖集

* 4.简单割和极小点覆盖集可以相互转换
    简单割可以转换为极小点覆盖集
    极小点覆盖集可以转换为简单割

* 本题:
    建图：拆点，将所有点拆分为出点和入点，所有的出点作为二分图的左部，入点作为二分图的右部
    建立源点 s 和汇点 t，对于原图中的一条有向边 x−>y，
    要将这条边移除，可以是 Wx−（从 x 射出的边的代价） 的代价，
                 也可以是 Wy+（射入 y 的边的代价） 的代价
    对应流网络中 s 向所有这样的 x 连一条容量为 Wx− 的边，
                    所有这样的 y 向 t 连一条容量为 Wy+ 的边，其余边容量足够大即可
*/
#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
using namespace std;
const int N = 210, M = 5200*2+10, INF = 0x3f3f3f3f;
int n, m, S, T;
int h[N], ne[M], c[M], e[M], idx;
int d[N], q[N], cur[N];
bool vis[N]; //属于S集合

void AddEdge(int a, int b, int w)
{
    e[idx] = b, c[idx] = w, ne[idx] = h[a], h[a] = idx++;
    e[idx] = a, c[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}

bool bfs()
{
    int hh = 0, tt = -1;
    memset(d, -1, sizeof d);
    q[++tt] = S, cur[S] = h[S], d[S] = 0;
    while(hh <= tt)
    {
        int u = q[hh++];
        for(int i = h[u]; ~i; i = ne[i])
        {
            int v = e[i];
            if(d[v] == -1 && c[i])
            {
                d[v] = d[u] + 1;
                cur[v] = h[v];
                if(v == T) return true;
                q[++tt] = v;
            }
        }
    }
    return false;
}

int find(int u, int limit)
{
    if(u == T) return limit;
    int flow = 0;
    for(int i = cur[u]; ~i && limit > flow; cur[u] = i, i = ne[i])
    {
        int v = e[i];
        if(d[v] == d[u] + 1 && c[i])
        {
            int t = find(v, min(c[i], limit - flow));
            if(!t) d[v] = -1;
            c[i] -= t, c[i^1] += t, flow += t;
        }
    }
    return flow;
}

int Dinic() 
{
    int res = 0, flow = 0;
    while(bfs())
        while((flow = find(S, INF))) res += flow;
    return res; 
}

void dfs(int u) //找出最小割，能从源点搜到的点属于S集合，反之属于T集合
{
    vis[u] = true;
    for(int i = h[u]; ~i; i=ne[i])
        if(!vis[e[i]] && c[i])  dfs(e[i]);

}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt", "r", stdin);
    #else
        ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    #endif

    memset(h, -1, sizeof h);
    cin >> n >> m;
    S = 0, T = 2*n+1;
    //左部节点为 +，编号 1 ~ n，右部节点为 -，编号 n + 1 ~ 2 * n

    for(int i=1; i<=n; i++) //射入该点的边
    {
        int w; cin >> w; AddEdge(S, i, w); //虚拟源点向当前点
    }
   
    for(int i=1; i<=n; i++) //该点射出的边
    {
        int w; cin >> w; AddEdge(i+n, T, w); //当前点向虚拟汇点
    }

    for(int i=1; i<=m; i++)
    {
        int a, b; cin >> a >> b; AddEdge(b, a+n, INF); //从 b+ 向 a- 连一条容量为 INF 的边
    }

    printf("%d\n", Dinic()); //最小权点覆盖 = 最小割

    dfs(S);

    int cnt = 0;
    for(int i=0; i<idx; i+=2)
    {
        int x=e[i^1], y=e[i];
        if(vis[x] && !vis[y]) cnt++; //执行步数
    }

    printf("%d\n", cnt);
    for(int i=0; i<idx; i+=2)
    {
        int x=e[i^1], y=e[i];
        if(vis[x] && !vis[y] && x==S) printf("%d +\n", y); //射入点i的边
    }

    for(int i=0; i<idx; i+=2)
    {
        int x=e[i^1], y=e[i];
        if(vis[x] && !vis[y] && y==T) printf("%d -\n", x-n); //从点i射出的边
    }
    return 0;
}